package com.drawingtimer.admin.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.drawingtimer.admin.enums.BizErrorCodeEnum;
import com.drawingtimer.admin.exception.BizException;
import com.drawingtimer.admin.mapper.TProcessInfoMapper;
import com.drawingtimer.admin.model.entity.TProcessFlowCard;
import com.drawingtimer.admin.model.entity.TProcessInfo;
import com.drawingtimer.admin.model.entity.TTimeSegmentRecord;
import com.drawingtimer.admin.model.from.TTimeSegmentRecordFrom;
import com.drawingtimer.admin.model.vo.TTimeSegmentRecordPageVO;
import com.drawingtimer.admin.model.qo.TTimeSegmentRecordQO;
import com.drawingtimer.admin.mapper.TTimeSegmentRecordMapper;
import com.drawingtimer.admin.service.TProcessFlowCardService;
import com.drawingtimer.admin.service.TProcessInfoService;
import com.drawingtimer.admin.service.TTimeSegmentRecordService;
import com.drawingtimer.admin.utils.http.HTTP;
import com.hccake.ballcat.common.model.domain.PageParam;
import com.hccake.ballcat.common.model.domain.PageResult;
import com.hccake.extend.mybatis.plus.service.impl.ExtendServiceImpl;
import lombok.extern.slf4j.Slf4j;
import netscape.javascript.JSObject;
import org.apache.commons.compress.utils.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

/**
 * 时间段记录
 *
 * @author jjh 2025-04-24 16:34:17
 */
@Service
@Slf4j
public class TTimeSegmentRecordServiceImpl extends ExtendServiceImpl<TTimeSegmentRecordMapper, TTimeSegmentRecord>
		implements TTimeSegmentRecordService {

	@Autowired
	private HTTP http;

	@Autowired
	private TProcessInfoMapper tProcessInfoMapper;

	@Autowired
	private TProcessFlowCardService tProcessFlowCardService;

	@Value("${plm.host}")
	private String plmHost;

	/**
	 * 根据QueryObeject查询分页数据
	 * @param pageParam 分页参数
	 * @param qo 查询参数对象
	 * @return PageResult<TTimeSegmentRecordPageVO> 分页数据
	 */
	@Override
	public PageResult<TTimeSegmentRecordPageVO> queryPage(PageParam pageParam, TTimeSegmentRecordQO qo) {
		return baseMapper.queryPage(pageParam, qo);
	}

	@Override
	public boolean updateStartTimer(TTimeSegmentRecordFrom from) {
		LambdaQueryWrapper<TTimeSegmentRecord> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(TTimeSegmentRecord::getFlowCardNumber, from.getFlowCardNumber())
			.eq(TTimeSegmentRecord::getProcessId, from.getProcessId());
		List<TTimeSegmentRecord> list = baseMapper.selectList(queryWrapper);
		if (CollectionUtil.isEmpty(list)) {
			TTimeSegmentRecord timeSegmentRecord = new TTimeSegmentRecord();
			BeanUtils.copyProperties(from, timeSegmentRecord);
			return baseMapper.insert(timeSegmentRecord) > 0;
		}
		return false;
	}

	@Override
	@Transactional
	public boolean updateEndTimer(TTimeSegmentRecordFrom tTimeSegmentRecord) {
		LambdaUpdateWrapper<TTimeSegmentRecord> updateWrapper = new LambdaUpdateWrapper<>();
		updateWrapper.eq(TTimeSegmentRecord::getFlowCardNumber, tTimeSegmentRecord.getFlowCardNumber())
			.eq(TTimeSegmentRecord::getProcessId, tTimeSegmentRecord.getProcessId())
			.isNull(TTimeSegmentRecord::getEndTime)
			.set(TTimeSegmentRecord::getEndTime, tTimeSegmentRecord.getEndTime());

		LambdaUpdateWrapper<TProcessInfo> tProcessInfoUpdateWrapper = new LambdaUpdateWrapper<>();
		tProcessInfoUpdateWrapper.eq(TProcessInfo::getId, tTimeSegmentRecord.getProcessId())
			.eq(TProcessInfo::getFlowCardNumber, tTimeSegmentRecord.getFlowCardNumber())
			.set(TProcessInfo::getCompletedQuantity, tTimeSegmentRecord.getFinishedQuantity())
			.set(TProcessInfo::getScrappedQuantity, tTimeSegmentRecord.getDefectiveQuantity())
			.set(TProcessInfo::getStatus, 3)
			.set(TProcessInfo::getScrapReason, tTimeSegmentRecord.getDefectiveReason());

		return tProcessInfoMapper.update(new TProcessInfo(), tProcessInfoUpdateWrapper) > 0
				&& baseMapper.update(new TTimeSegmentRecord(), updateWrapper) > 0;
	}

	@Override
	public ByteArrayResource getPlmProgramFile(TTimeSegmentRecordQO qo) {
		final List<Integer> validTypes = Arrays.asList(0, 1, 2, 3);

		if (qo.getType() == null || !validTypes.contains(qo.getType())
				|| StringUtils.isBlank(qo.getProcessCardNumber())) {
			throw new BizException(BizErrorCodeEnum.PARAM_INVALID);
		}

		TProcessFlowCard processFlowCard = tProcessFlowCardService.getByProcessCardNumber(qo.getProcessCardNumber());
		if (processFlowCard == null) {
			throw new BizException(BizErrorCodeEnum.PROCESS_CARD_NOT_FOUND);
		}

		String materialCode = processFlowCard.getMaterialCode();
		if (StringUtils.isEmpty(materialCode)) {
			throw new BizException(BizErrorCodeEnum.MATERIAL_CODE_EMPTY);
		}

		String processCode = qo.getProcessCode();
		String processCardNumber = materialCode.substring(0, materialCode.length() - 2);

		if (Arrays.asList(1, 2, 3).contains(qo.getType())) {
			if (StringUtils.isEmpty(processCode)) {
				throw new BizException(BizErrorCodeEnum.PROCESS_CODE_EMPTY);
			}
			processCardNumber += "-" + processCode;
		}

		if (StringUtils.isEmpty(processCardNumber)) {
			throw new BizException(BizErrorCodeEnum.PROCESS_CARD_NUMBER_EMPTY);
		}

		String uri;
		switch (qo.getType()) {
			case 0:
				uri = "/CADOperation/Get2DCADSignFile";
				break;
			case 1:
				uri = "/ProcessCardOperation/GetProcessCardSignFile";
				break;
			case 2:
				uri = "/ProcessCardOperation/GetCNCFile";
				break;
			case 3:
				uri = "/ProcessCardOperation/GetCNCFile";
				break;
			default:
				uri = null;
				break;
		}

		Map<String, String> headers = new HashMap<>();
		headers.put("Content-Type", "application/json");

		Map<String, String> paramMap = new HashMap<>();
		paramMap.put("creatorGroup", "XMX");
		if (qo.getType() == 0) {
			paramMap.put("cadNumber", processCardNumber);
		}
		else {
			paramMap.put("ProcessCardNumber", processCardNumber);
		}

		try {
			String response = http.postJsonParam(plmHost + uri, headers, JSONObject.toJSONString(paramMap));
			JSONObject json = JSONObject.parseObject(response);

			if (!"0".equals(json.getString("Code"))) {
				throw new BizException(BizErrorCodeEnum.PLM_FILE_NOT_FOUND.getCode(), json.getString("ReturnValue"));
			}

			JSONObject returnValue = json.getJSONObject("ReturnValue");
			if (returnValue == null || returnValue.isEmpty()) {
				throw new BizException(BizErrorCodeEnum.PLM_RETURN_EMPTY);
			}

			String pdfUrl = null;

			if (qo.getType().equals(2)) {
				String firstKey = returnValue.keySet().iterator().next();
				JSONArray fileArray = returnValue.getJSONArray(firstKey);
				for (int i = 0; i < fileArray.size(); i++) {
					JSONObject pdfFile = fileArray.getJSONObject(i).getJSONObject("PDFFile");
					if (pdfFile != null) {
						String fileName = pdfFile.getString("FileName");
						if (StringUtils.isNotBlank(fileName) && fileName.toLowerCase().endsWith(".pdf")
								&& StringUtils.isNotBlank(pdfFile.getString("Url"))) {
							pdfUrl = pdfFile.getString("Url");
							break;
						}
					}
				}
			}
			else if (qo.getType().equals(3)) {
				String firstKey = returnValue.keySet().iterator().next();
				JSONArray fileArray = returnValue.getJSONArray(firstKey);
				for (int i = 0; i < fileArray.size(); i++) {
					JSONObject oriFile = fileArray.getJSONObject(i).getJSONObject("OriFile");
					if (oriFile != null) {
						String fileName = oriFile.getString("FileName");
						if (StringUtils.isNotBlank(fileName) && fileName.toLowerCase().contains(".nc")
								&& StringUtils.isNotBlank(oriFile.getString("Url"))) {
							pdfUrl = oriFile.getString("Url");
							break;
						}
					}
				}
			}
			else {
				String firstKey = returnValue.keySet().iterator().next();
				JSONObject pdfFile = returnValue.getJSONObject(firstKey).getJSONObject("PDFFile");
				if (pdfFile != null) {
					String fileName = pdfFile.getString("FileName");
					if (StringUtils.isNotBlank(fileName) && fileName.toLowerCase().endsWith(".pdf")
							&& StringUtils.isNotBlank(pdfFile.getString("Url"))) {
						pdfUrl = pdfFile.getString("Url");
					}
				}
			}

			if (StringUtils.isBlank(pdfUrl)) {
				log.warn("未获取到有效的 文件 URL");
				return null;
			}

			if (StringUtils.isBlank(pdfUrl)) {
				throw new BizException(BizErrorCodeEnum.PDF_URL_EMPTY);
			}

			try {
				URL url = new URL(pdfUrl);
				InputStream inputStream = url.openStream();
				byte[] bytes = IOUtils.toByteArray(inputStream);
				ByteArrayResource resource = new ByteArrayResource(bytes);
				return resource;
			}
			catch (MalformedURLException e) {
				throw new BizException(BizErrorCodeEnum.PDF_URL_INVALID, e);
			}
			catch (IOException e) {
				throw new BizException(BizErrorCodeEnum.PDF_DOWNLOAD_FAIL, e);
			}

		}
		catch (BizException e) {
			throw e;
		}
		catch (Exception e) {
			throw new BizException(BizErrorCodeEnum.PLM_CALL_FAIL, e);
		}
	}

	@Override
	public String getPlmProgramFileNC(TTimeSegmentRecordQO qo) {

		if (StringUtils.isBlank(qo.getProcessCardNumber())) {
			throw new BizException(BizErrorCodeEnum.PARAM_INVALID);
		}

		TProcessFlowCard processFlowCard = tProcessFlowCardService.getByProcessCardNumber(qo.getProcessCardNumber());
		if (processFlowCard == null) {
			throw new BizException(BizErrorCodeEnum.PROCESS_CARD_NOT_FOUND);
		}

		String materialCode = processFlowCard.getMaterialCode();
		if (StringUtils.isEmpty(materialCode)) {
			throw new BizException(BizErrorCodeEnum.MATERIAL_CODE_EMPTY);
		}

		String processCode = qo.getProcessCode();
		String processCardNumber = materialCode.substring(0, materialCode.length() - 2);
		processCardNumber += "-" + processCode;

		if (StringUtils.isEmpty(processCardNumber)) {
			throw new BizException(BizErrorCodeEnum.PROCESS_CARD_NUMBER_EMPTY);
		}

		String uri = "/ProcessCardOperation/GetCNCFile";

		Map<String, String> headers = new HashMap<>();
		headers.put("Content-Type", "application/json");

		Map<String, String> paramMap = new HashMap<>();
		paramMap.put("creatorGroup", "XMX");
		paramMap.put("ProcessCardNumber", processCardNumber);

		try {
			String response = http.postJsonParam(plmHost + uri, headers, JSONObject.toJSONString(paramMap));
			JSONObject json = JSONObject.parseObject(response);

			if (!"0".equals(json.getString("Code"))) {
				throw new BizException(BizErrorCodeEnum.PLM_FILE_NOT_FOUND.getCode(), json.getString("ReturnValue"));
			}

			JSONObject returnValue = json.getJSONObject("ReturnValue");
			if (returnValue == null || returnValue.isEmpty()) {
				throw new BizException(BizErrorCodeEnum.PLM_RETURN_EMPTY);
			}

			String firstKey = returnValue.keySet().iterator().next();
			JSONArray fileArray = returnValue.getJSONArray(firstKey);

			String pdfUrl = null;

			for (int i = 0; i < fileArray.size(); i++) {
				JSONObject oriFile = fileArray.getJSONObject(i).getJSONObject("OriFile");
				if (oriFile != null) {
					String fileName = oriFile.getString("FileName");
					if (StringUtils.isNotBlank(fileName) && fileName.toLowerCase().contains(".nc")
							&& StringUtils.isNotBlank(oriFile.getString("Url"))) {
						pdfUrl = oriFile.getString("Url");
						break;
					}
				}
			}

			if (StringUtils.isBlank(pdfUrl)) {
				log.warn("未获取到有效的 文件 URL");
				return null;
			}

			if (StringUtils.isBlank(pdfUrl)) {
				throw new BizException(BizErrorCodeEnum.PDF_URL_EMPTY);
			}

			return pdfUrl;

		}
		catch (BizException e) {
			throw e;
		}
		catch (Exception e) {
			throw new BizException(BizErrorCodeEnum.PLM_CALL_FAIL, e);
		}
	}

	public TTimeSegmentRecord getByRecordId(Long recordId) {
		LambdaQueryWrapper<TTimeSegmentRecord> queryWrapper = new LambdaQueryWrapper<>();
		queryWrapper.eq(TTimeSegmentRecord::getProcessId, recordId);
		return baseMapper.selectOne(queryWrapper);
	}

}
